package com.schoolComments.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.schoolComments.dto.LoginFormDTO;
import com.schoolComments.dto.Result;
import com.schoolComments.dto.UserDTO;
import com.schoolComments.entity.User;
import com.schoolComments.mapper.UserMapper;
import com.schoolComments.service.IUserService;
import com.schoolComments.utils.RegexUtils;
import com.schoolComments.utils.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 服务实现类
 * </p>
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Resource
    private UserMapper userMapper;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Override
    public Result sendCode(String phone) {
        //验证手机号
        if (RegexUtils.isPhoneInvalid(phone)) {
            //手机号不符合要求
            return Result.fail("手机号格式不正确");
        }
        //生成验证码
        String code = RandomUtil.randomNumbers(6);
        //将验证码存入redis 并设置一个过期时间
        stringRedisTemplate.opsForValue().set(phone, code, 2, TimeUnit.MINUTES);
        //发送验证码
        //此处模拟输出一下即可
        log.info("验证码:  " + code);
        return Result.ok();
    }

    @Override
    public Result login(LoginFormDTO loginForm) {
        //查看验证码是否正确
        String code = stringRedisTemplate.opsForValue().get(loginForm.getPhone());
        if (code == null || !code.equals(loginForm.getCode())) {
            //不正确
            return Result.fail("验证码错误");
        }
        //检查手机号是否为新用户
        User user = userMapper.selectUsernameByPhone(loginForm.getPhone());
        //是新用户 将该用户信息存入数据库
        if(user == null){
            user = new User();
            user.setCreateTime(LocalDateTime.now());
            user.setUpdateTime(LocalDateTime.now());
            user.setPhone(loginForm.getPhone());
            user.setNickName("user_"+RandomUtil.randomString(4));
            userMapper.insertUser(user);
        }
        //为了保护用户隐私 将user对象转换为UserDTO对象后存入redis 以此屏蔽用户详情信息
        UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);

        //将用户信息存入redis

        /*这里存入redis的key 要求唯一 且这个key要返回给前端 存入阅览器的内存中 (以后请求的时候 前端会携带这个key去redis里找相应的信息)
        所以要求这个key要安全 如果用手机号 会不安全 所以用一个随机的token来做key
        至于value的选择 用json串的话会有很多不必要信息(标点。。) 且不好修改 要修改只能覆盖
        用hashmap则可以解决这些问题*/

        // 生成一个随机的token
        String token = UUID.randomUUID().toString();
        //将userDto对象转换为hashmap
        //redis的hashmap中要的都是<String, String> 而userDto中id为Long(转换后为<String, Long>) 所以要转换为String后在存入
        Map<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),
                CopyOptions.create().
                        setIgnoreNullValue(true).
                        setFieldValueEditor((fileName, fileValue) -> (fileValue.toString()))
        );
        //存入redis
        String tokenKey = "userLogin:token:" + token;
        stringRedisTemplate.opsForHash().putAll(tokenKey, userMap);
        //设置一下过期时间
        stringRedisTemplate.expire(tokenKey, 30, TimeUnit.MINUTES);
        //返回token给前端
        return Result.ok(token);
    }

    @Override
    public UserDTO me() {
        return UserHolder.getUser();
    }

    @Override
    public Result queryUserById(Long id) {
        Set<String> ids = new HashSet<>();
        ids.add(id+"");
        List<UserDTO> userDTOS1 = userMapper.queryUsersByIds(ids);
        if (userDTOS1!=null && !userDTOS1.isEmpty()) {
            return Result.ok(userDTOS1.get(0));
        }
        else{
            return Result.fail("用户不存在");
        }
    }
}
